package ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.visitors;

import java.util.Iterator;

import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.Expresion;
import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.And;
import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.False;
import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.Or;
import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.True;

/**
 * Aplica algunos de los teoremas de reduccion mientras evalua las expresiones 
 * 
 * @author Juan F. Codagnone
 * @since Apr 4, 2010
 */
public class EditorEvalVisitorCallback extends EvalVisitorCallback {
    private static final Expresion T = new True();
    private static final Expresion F = new False();
    
    /** @param cases */
    public EditorEvalVisitorCallback(final boolean[][] cases) {
        super(cases);
    }

    /** Creates the Foo. */
    public EditorEvalVisitorCallback(final int variables) {
        super(variables);
    }

    /** @see EvalVisitorCallback#onEval(Expresion, boolean[][]) */
    @Override
    protected final Expresion onEval(final Expresion e, final boolean[][]args) {
        Expresion ret = null;
        
        if((e instanceof And || e instanceof Or) && args.length == 2) {
            final boolean []isTrue =  {true, true};
            final boolean []isFalse = {false, false};
            boolean isEquals = true;
            
            for(int i = 0; i < args[0].length; i++) {
                for(int j = 0; j < isTrue.length; j++) {
                    isTrue[j] &= args[j][i];
                    isFalse[j] |= args[j][i];
                }
                isEquals &= args[0][i] == args[1][i]; 
            }
            isFalse[0] = !isFalse[0];
            isFalse[1] = !isFalse[1];
            
            // T3: X + X = X
            // T3' = X . X = X
            if(isEquals) {
                Expresion shortest = null;
                int min = Integer.MAX_VALUE;
                for(final Expresion child : e) {
                    if(shortest == null) {
                        shortest = child;
                    }
                    final int lenght = new CountVisitorCallback().eval(child);
                    if(lenght < min) {
                        min = lenght;
                        shortest = child;
                    }
                }
                ret = shortest;
            } else if(isFalse[0] | isFalse[1]) {
                if(e instanceof And) {
                    // T2' X . 0 = 0
                    ret = F;
                } else if(e instanceof Or) {
                    // T1 = X + 0 = X
                    final Iterator<Expresion> i = e.iterator();
                    final Expresion a = i.next();
                    final Expresion b = i.next();
                    
                    ret = isFalse[0] ? a : b; 
                }
            } else if(isTrue[0] | isTrue[1]) {
                if(e instanceof And) {
                    // T1' X . 1 = X
                    final Iterator<Expresion> i = e.iterator();
                    final Expresion a = i.next();
                    final Expresion b = i.next();
                    
                    ret = isTrue[0] ? a : b;
                } else if(e instanceof Or) {
                    // T2 = X + 1 = 1
                    ret = T;
                }
            }
        }
        
        return ret;
    }
}
